﻿using Microsoft.EntityFrameworkCore;

namespace Devonline.Identity;

public static class IdentityExtensions
{
    /// <summary>
    /// 针对字符串类型主键的 IIdentity 实例获取对应的 IdentityType
    /// </summary>
    /// <param name="identity"></param>
    /// <returns></returns>
    public static IdentityType GetIdentityType(this IIdentity<string> identity) => identity.GetIdentityType<string>();

    /// <summary>
    /// 针对 IIdentity<TKey> 实例获取对应的 IdentityType
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <param name="identity"></param>
    /// <returns></returns>
    public static IdentityType GetIdentityType<TKey>(this IIdentity<TKey> identity) where TKey : IConvertible, IEquatable<TKey> => identity.GetIdentityType<IIdentity<TKey>, TKey>();

    /// <summary>
    /// 针对任意引用类型获取对应的身份 IdentityType
    /// </summary>
    /// <typeparam name="TIdentity"></typeparam>
    /// <param name="identity"></param>
    /// <returns></returns>
    public static IdentityType GetIdentityType<TIdentity, TKey>(this TIdentity identity) where TIdentity : class, IIdentity<TKey> where TKey : IConvertible, IEquatable<TKey> => identity switch
    {
        User<TKey> => IdentityType.User,
        Role<TKey> => IdentityType.Role,
        Group<TKey> => IdentityType.Group,
        Level<TKey> => IdentityType.Level,
        _ => IdentityType.System
    };

    /// <summary>
    /// 根据身份类型和编号获取对应的用户
    /// </summary>
    /// <typeparam name="TKey">主键类型</typeparam>
    /// <param name="context">身份数据库上下文</param>
    /// <param name="identityType">身份分配类型</param>
    /// <param name="identities">身份编号</param>
    /// <returns></returns>
    public static async Task<List<User<TKey>>> GetUsersByIdentityType<TKey>(this IdentityDbContext<TKey> context, IdentityType identityType, params TKey[] identities) where TKey : IConvertible, IEquatable<TKey>
    {
        List<User<TKey>> users = null;
        if (identities.IsNotNullOrEmpty())
        {
            switch (identityType)
            {
                case IdentityType.User:
                    users = await context.Users.Where(x => x.State == DataState.Available && identities.Contains(x.Id)).ToListAsync();
                    break;
                case IdentityType.Role:
                    users = await context.Users.Where(x => context.UserRoles.Where(a => identities.Contains(a.RoleId)).Select(a => a.UserId).Contains(x.Id)).ToListAsync();
                    break;
                case IdentityType.Group:
                    users = await context.Users.Where(x => context.UserGroups.Where(a => identities.Contains(a.GroupId)).Select(a => a.UserId).Contains(x.Id)).ToListAsync();
                    break;
                default:
                    break;
            }
        }

        return users;
    }

    /// <summary>
    /// 根据身份类型和编号获取对应的用户
    /// </summary>
    /// <param name="context">身份数据库上下文</param>
    /// <param name="identityType">身份分配类型</param>
    /// <param name="identities">身份编号</param>
    public static async Task<List<User>> GetUsersByIdentityType(this IdentityDbContext context, IdentityType identityType, params string[] identities)
    {
        List<User> users = null;
        if (identities.IsNotNullOrEmpty())
        {
            switch (identityType)
            {
                case IdentityType.User:
                    users = await context.Users.Where(x => x.State == DataState.Available && identities.Contains(x.Id) || identities.Contains(x.UserName)).ToListAsync();
                    break;
                case IdentityType.Role:
                    var roleIds = await context.Roles.Where(x => x.State == DataState.Available && identities.Contains(x.Id) || identities.Contains(x.Name)).Select(x => x.Id).ToListAsync();
                    if (roleIds.IsNotNullOrEmpty())
                    {
                        users = await context.Users.Where(x => context.UserRoles.Where(a => roleIds.Contains(a.RoleId)).Select(a => a.UserId).Contains(x.Id)).ToListAsync();
                    }
                    break;
                case IdentityType.Group:
                    var groupIds = await context.Groups.Where(x => x.State == DataState.Available && identities.Contains(x.Id) || identities.Contains(x.Name)).Select(x => x.Id).ToListAsync();
                    if (groupIds.IsNotNullOrEmpty())
                    {
                        users = await context.Users.Where(x => context.UserGroups.Where(a => groupIds.Contains(a.GroupId)).Select(a => a.UserId).Contains(x.Id)).ToListAsync();
                    }
                    break;
                default:
                    break;
            }
        }

        return users;
    }
}
